Using icsound

By: Andres Cabrera mantaraya36@gmail.com

Starting the Csound engine

To use icsound create an icsound instance:


In [1]:
%pylab inline


Populating the interactive namespace from numpy and matplotlib

In [2]:
import icsound
cs = icsound.icsound()

Then start the engine:


In [3]:
cs.start_engine()


Csound server started.

You can set the properties of the Csound engine with parameters to the start_engine() function.


In [4]:
help(cs.start_engine)


Help on method start_engine in module icsound:

start_engine(self, sr=44100, ksmps=64, nchnls=2, zerodbfs=1.0, dacout='dac', adcin=None, port=None, buffersize=None) method of icsound.icsound instance
    Start the csound engine on a separate thread

The engine runs in a separate thread, so it doesn't block execution of python.


In [5]:
cs.start_engine()


icsound: Csound already running

Use the %%csound magic command to directly type csound language code in the cell and send it to the current engine.


In [6]:
%%csound
gkinstr init 1

In [7]:
%%csound
print i(gkinstr)

So where did it print?


In [8]:
cs.print_log()


WARNING: STK opodes not available: define environment variable RAWWAVE_PATH
(points to rawwaves directory) to use STK opcodes.
rtaudio: ALSA module enabled
rtmidi: ALSA Raw MIDI module enabled
--Csound version 6.05 (double samples) Jul 12 2015
graphics suppressed, ascii substituted
0dBFS level = 1.0
orch now loaded
audio buffered in 256 sample-frame blocks
ALSA output: total buffer size: 1024, period size: 256 
writing 512 sample blks of 64-bit floats to dac 
SECTION 1:
instr 0:  #i0 = 1.000

By default, messages from Csound are not shown, but they are stored in an internal buffer. You can view them with the print_log() function. If the log is getting too long and cinfusing, use the clear_log() function.

Function tables

You can create csound f-tables directly from python lists or numpy arrays:


In [9]:
cs.fill_table(1, [4,5,7,0,8,7,9])
cs.fill_table(2, array([8,7,9, 1, 1, 1]))

Tables can be plotted in the usual matplotlib way, but icsound provides a plot_table function which styles the graphs.


In [10]:
cs.plot_table(1)
cs.plot_table(2, reuse=True)
grid()


You can get the function table values from the csound instance:


In [11]:
cs.get_table_data(1)


Out[11]:
array([ 4.,  5.,  7.,  0.,  8.,  7.], dtype=float32)

In [12]:
cs.make_table(2, 1024, 10, 1)
cs.make_table(3, 1024, -10, 0.5, 1)
cs.plot_table(2)
cs.plot_table(3, reuse=True)
#ylim((-1.1,1.1))



In [13]:
cs.get_table_data(2)[100: 105]


Out[13]:
array([ 0.57580817,  0.58081394,  0.58579785,  0.59075969,  0.59569931], dtype=float32)

If ctypes is available in your system, icsound will use it to significantly speed up data transfer to and from Csound f-tables. The following will create 320 tables with 720 points each:


In [14]:
randsig = random.random((320, 720))
i = 0
for i,row in enumerate(randsig):
    cs.fill_table(50 + i, row)
    print i, '..',


0 .. 1 .. 2 .. 3 .. 4 .. 5 .. 6 .. 7 .. 8 .. 9 .. 10 .. 11 .. 12 .. 13 .. 14 .. 15 .. 16 .. 17 .. 18 .. 19 .. 20 .. 21 .. 22 .. 23 .. 24 .. 25 .. 26 .. 27 .. 28 .. 29 .. 30 .. 31 .. 32 .. 33 .. 34 .. 35 .. 36 .. 37 .. 38 .. 39 .. 40 .. 41 .. 42 .. 43 .. 44 .. 45 .. 46 .. 47 .. 48 .. 49 .. 50 .. 51 .. 52 .. 53 .. 54 .. 55 .. 56 .. 57 .. 58 .. 59 .. 60 .. 61 .. 62 .. 63 .. 64 .. 65 .. 66 .. 67 .. 68 .. 69 .. 70 .. 71 .. 72 .. 73 .. 74 .. 75 .. 76 .. 77 .. 78 .. 79 .. 80 .. 81 .. 82 .. 83 .. 84 .. 85 .. 86 .. 87 .. 88 .. 89 .. 90 .. 91 .. 92 .. 93 .. 94 .. 95 .. 96 .. 97 .. 98 .. 99 .. 100 .. 101 .. 102 .. 103 .. 104 .. 105 .. 106 .. 107 .. 108 .. 109 .. 110 .. 111 .. 112 .. 113 .. 114 .. 115 .. 116 .. 117 .. 118 .. 119 .. 120 .. 121 .. 122 .. 123 .. 124 .. 125 .. 126 .. 127 .. 128 .. 129 .. 130 .. 131 .. 132 .. 133 .. 134 .. 135 .. 136 .. 137 .. 138 .. 139 .. 140 .. 141 .. 142 .. 143 .. 144 .. 145 .. 146 .. 147 .. 148 .. 149 .. 150 .. 151 .. 152 .. 153 .. 154 .. 155 .. 156 .. 157 .. 158 .. 159 .. 160 .. 161 .. 162 .. 163 .. 164 .. 165 .. 166 .. 167 .. 168 .. 169 .. 170 .. 171 .. 172 .. 173 .. 174 .. 175 .. 176 .. 177 .. 178 .. 179 .. 180 .. 181 .. 182 .. 183 .. 184 .. 185 .. 186 .. 187 .. 188 .. 189 .. 190 .. 191 .. 192 .. 193 .. 194 .. 195 .. 196 .. 197 .. 198 .. 199 .. 200 .. 201 .. 202 .. 203 .. 204 .. 205 .. 206 .. 207 .. 208 .. 209 .. 210 .. 211 .. 212 .. 213 .. 214 .. 215 .. 216 .. 217 .. 218 .. 219 .. 220 .. 221 .. 222 .. 223 .. 224 .. 225 .. 226 .. 227 .. 228 .. 229 .. 230 .. 231 .. 232 .. 233 .. 234 .. 235 .. 236 .. 237 .. 238 .. 239 .. 240 .. 241 .. 242 .. 243 .. 244 .. 245 .. 246 .. 247 .. 248 .. 249 .. 250 .. 251 .. 252 .. 253 .. 254 .. 255 .. 256 .. 257 .. 258 .. 259 .. 260 .. 261 .. 262 .. 263 .. 264 .. 265 .. 266 .. 267 .. 268 .. 269 .. 270 .. 271 .. 272 .. 273 .. 274 .. 275 .. 276 .. 277 .. 278 .. 279 .. 280 .. 281 .. 282 .. 283 .. 284 .. 285 .. 286 .. 287 .. 288 .. 289 .. 290 .. 291 .. 292 .. 293 .. 294 .. 295 .. 296 .. 297 .. 298 .. 299 .. 300 .. 301 .. 302 .. 303 .. 304 .. 305 .. 306 .. 307 .. 308 .. 309 .. 310 .. 311 .. 312 .. 313 .. 314 .. 315 .. 316 .. 317 .. 318 .. 319 ..

In [15]:
cs.plot_table(104)


Sending instruments

You can send instruments to the running csound engine with the %%csound magic. Any syntax errors will be displayed inline.


In [16]:
%%csound
instr 1
asig asds


error: syntax error, unexpected T_IDENT  (token "asds") line 3:
>>>asig asds <<<
Unexpected untyped word asig when expecting a variable
Parsing failed due to invalid input!
Stopping on parser failure


In [17]:
%%csound
instr 1
asig oscil 0.5, 440
outs asig, asig


error: syntax error, unexpected $end  (token "") line 6:
>>>outs asig, asig <<<
Parsing failed due to invalid input!
Stopping on parser failure


In [18]:
%%csound
instr 1
asig oscil 0.5, 440
outs asig, asig
endin

Channels

Csound channels can be used to send values to Csound. They can affect running instances of instruments by using the invalue/chnget opcodes:


In [21]:
cs.set_channel("val", 20)

You can also read the channels from Csound. These channels can be set from icsound or within instruments with the outvalue/chnset opcodes:


In [22]:
cs.get_channel("val")


Out[22]:
20.0

Recording the output

You can record the realtime output from csound: (This requires Csound 6.04 - unrealeased as of this writing...)


In [23]:
cs.start_record("out.wav")

In [24]:
cs.send_score("i 1 0 1")
import time
time.sleep(1)

In [25]:
cs.stop_record()

In [26]:
!aplay out.wav


Playing WAVE 'out.wav' : Signed 16 bit Little Endian, Rate 44100 Hz, Stereo

Remote engines

You can also interact with engines through UDP. Note that not all operations are available, notably reading f-tables, but you can send instruments and note events to the remote engine.


In [ ]:
cs_client = icsound.icsound()
cs_client.start_client()

In [ ]:
cs.clear_log()

Now send notes and instruments from the client:


In [ ]:
cs_client.send_score("i 1 0 1")
cs_client.send_code("print i(gkinstr)")

And show the log in the server:


In [ ]:
cs.print_log()

Stopping the engine


In [ ]:
cs.stop_engine()

In [ ]:
cs

In [ ]:
cs.stop_engine()

Audification

Reading Earthquake data through a web API:


In [27]:
prefix = 'http://service.iris.edu/irisws/timeseries/1/query?'
SCNL_parameters = 'net=IU&sta=ANMO&loc=00&cha=BHZ&'
times = 'starttime=2005-01-01T00:00:00&endtime=2005-01-02T00:00:00&'
output = 'output=ascii'
import urllib2
f = urllib2.urlopen(prefix + SCNL_parameters + times + output)
timeseries = f.read()

In [28]:
data = timeseries.split('\n')
dates = []
values = []

for line in data[1:-1]:
    date, val = line.split()
    dates.append(date)
    values.append(float(val))

plot(values)


Out[28]:
[<matplotlib.lines.Line2D at 0x7fd4b55d4790>]

In [29]:
cs.start_engine()
cs.fill_table(1, values)


icsound: Csound already running

Instrument to play back the earthquake data stored in a table:


In [30]:
%%csound
instr 1
idur = p3
itable = p4
asig poscil 1/8000, 1/p3, p4
outs asig, asig
endin

Listen:


In [32]:
cs.send_score('i 1 0 3 1')

Slower:


In [33]:
cs.send_score('i 1 0 7 1')

In [34]:
cs.send_score('i 1 0 1 1')

Parameter mapping sonification

Get financial data through a web API:


In [35]:
import xml.etree.ElementTree as ET
import urllib2
from datetime import datetime

symbols = 'MSFT', 'GOOG'

data = {}

for symbol in symbols:
    url = 'http://chartapi.finance.yahoo.com/instrument/1.0/' + \
        symbol + '/chartdata;type=quote;range=1y/xml'
    f = urllib2.urlopen(url)
    root = ET.fromstring(f.read())
    
    dates = []
    values = []
    for v in root[2].findall('p'):
        dateval = v.attrib['ref']
        date = datetime(year=int(dateval[0:4]), month=int(dateval[4:6]), day=int(dateval[6:8])) 
        dates.append(date)
        entryvalues = []
        for num in v:
            entryvalues.append(float(num.text))
        values.append(entryvalues)
    data[symbol] = [dates, array(values)]

In [36]:
cs.fill_table(1,data['GOOG'][1][:,1] - min(data['GOOG'][1][:,1]) )
cs.fill_table(2,data['MSFT'][1][:,1] - min(data['MSFT'][1][:,1]) )

In [37]:
cs.plot_table(1)
title('GOOG')


Out[37]:
<matplotlib.text.Text at 0x7fd4b56a0d90>

In [38]:
cs.plot_table(2)
title('MSFT')


Out[38]:
<matplotlib.text.Text at 0x7fd4b54b5cd0>

In [39]:
%%csound
gisine ftgen 0, 0, 4096, 10, 1

instr 5

    amoddepth poscil 1/2, 1/p3, 2
    acarfreq poscil 3, 1/p3, 1
    acmratio = amoddepth*10

    aphs phasor 220 + acarfreq
    
    aphsmod oscili amoddepth/2, acarfreq*( acmratio)

    asig table3 aphs + aphsmod, gisine, 1, 0, 1
    aenv linen 0.2, 0.01, p3, 0.01
    outs asig*aenv, asig*aenv

endin

In [40]:
cs.send_score('i 5 0 20')

In [ ]:
cs.send_score('i -5 0 20')

In [41]:
%%csound
gisine ftgen 0, 0, 4096, 10, 1

instr 7

    kratiofactor chnget "factor"
    amoddepth poscil 1/2, 1/p3, 2
    acarfreq poscil 3, 1/p3, 1
    acmratio = amoddepth*kratiofactor

    aphs phasor 220 + acarfreq
    
    aphsmod oscili amoddepth/2, acarfreq*( acmratio)

    asig table3 aphs + aphsmod, gisine, 1, 0, 1
    aenv linen 0.2, 0.01, p3, 0.01
    outs asig*aenv, asig*aenv

endin

In [42]:
cs.send_score('i 7 0 40')

In [45]:
cs.set_channel("factor", 0.1)

In [46]:
cs.plot_table(1)
cs.plot_table(2)


Other tests

Another engine:


In [ ]:
ics = icsound.icsound()

In [ ]:
ics.start_engine(buffersize=64)

In [ ]:
ics.list_interfaces()

In [ ]:
%%csound

instr 1
asig oscil 0.5, 440
outs asig, asig
endin

In [ ]:
ics.send_score("i 1 0 0.5")

In [ ]:
ics.stop_engine()

In [ ]:
del ics